#include<assert.h>
#include<iostream>
#include<typeinfo>
#include<algorithm>

#include<string>

class Any
{
private:
    class placeholder
    {
    public:
        virtual ~placeholder() {}
        virtual const std::type_info& type() = 0;
        virtual placeholder* clone() = 0;
    };
    //使用这种方式主要是为了绕过模板的编译期确定类型！
    //让其可以直接定义出来一个any对象，而不是要以any<int>这样的方式才能定义出来一个对象！
    //在需要的时候我们只要通过管理子类holder，通过模板去生成一个我们需要的类型！

    template <class T>
    class holder:public placeholder
    {
    public:
        holder(const T &value)
            : _val(value)
        { }

        virtual const std::type_info& type() //获取子类对象保存的类型！
        {
            return typeid(T);
            //因为type_info的拷贝构造被禁用！只能使用typeid创建出来一个对象！
            // 所以我们必须返回它的引用！
        }

        virtual placeholder* clone()//针对当前的对象自身克隆出一个新的子类对象！
        {
            return new holder(_val);
        }

        T _val;
    };
    placeholder* _content;


public:
    Any():_content(nullptr) {}

    template <class T>
    Any(const T &val)
        : _content(new holder<T>(val))
    {
    }

    Any(const Any &others)//拷贝构造
        : _content(others._content ? others._content->clone() : nullptr)
    {
    }

    ~Any()
    {
        delete _content;
    }

    Any& swap(Any& ohter)
    {
        std::swap(_content,ohter._content);
        return *this;
    }

    template <class T>
    T *get() // 返回保存的数据的指针！
    {
        assert(typeid(T) == _content->type());//获取的数据类型和我们保存的据类型是要一致的！
        return &(((holder<T> *)_content)->_val);

    }

    template<class T>
    Any& operator=(const T& val)//重载赋值运算符，让其可以接收各种类型的赋值！
    {
        //为val构建一个临时通用容器！然后与容器自身进行交换！
        //当出了作用域后，临时对象释放的时候，原先保存的资源也会一起被释放！
        Any(val).swap(*this);
        return *this;
    }

    Any& operator=(Any other)//同类型的赋值！
    {
        //形参本身就是一个临时对象！
        other.swap(*this);
        return *this;
    }
};

class Test{//测试是否内存泄漏
    public:
        Test()
        {
            std::cout << "test" << std::endl;
        }
        Test(const Test &t)
        {
            std::cout << "test(Test&)" << std::endl;
        }
        ~Test()
        {
            std::cout << "~test" << std::endl;
        }
};

// int main()
// {
//     Any a;
//     // a = 10;
//     // std::cout << *(a.get<int>()) <<std::endl;

//     // Any b = std::string("string");

//     // std::cout << *(b.get<std::string>()) <<std::endl;

//     // a = b;
//     // std::cout << *(a.get<std::string>()) <<std::endl;
//     {
//         Test t;
//         a = t;
//     }


//     return 0;
// }


























